package org.bx.idgenerator.base.segment.buffer;

import lombok.extern.slf4j.Slf4j;
import org.bx.idgenerator.base.segment.ILeafInfoService;
import org.bx.idgenerator.base.segment.Segment;
import org.bx.idgenerator.base.segment.bean.IDWrapper;
import org.bx.idgenerator.base.segment.bus.FillSegmentEvent;
import org.bx.idgenerator.base.segment.bus.FillSegmentUpdater;
import org.bx.idgenerator.base.segment.policy.IFetchPolicy;
import org.bx.idgenerator.exception.BizException;
import sun.misc.Unsafe;

import java.lang.reflect.Field;


/**
 * ID段缓冲
 * @author 苏继宙
 * @version V1.0
 * @date: 2020年07月09日 15时54分
 */
@Slf4j
public class SegmentBuffer {

    /**
     *  状态
     *
     *  CAS 替换状态
     */
    public static final int CHANGE_NEXT_BUFFER = 3;

    /**
     *  正在填充
     */
    public static final int FILLED_NEXT_BUFFER = 2;
    /**
     *  正在填充
     */
    public static final int FILLING_NEXT_BUFFER = 1;
    public static final int NORMAL = 0;


    /**
     * 初始状态
     */
    private volatile int state = NORMAL;

    /**
     * 当前段缓存
     */
    private volatile Segment curSegment;

    /**
     * next 段缓存
     */
    private volatile Segment nextSegment;

    /**
     *  交互层  Mysql   Etcd
     */
    private final ILeafInfoService leafInfoService;

    /**
     *  state  偏移量
     */
    private static final long STATE_OFFSET;
    private static final Unsafe UNSAFE;


    /**
     *  segment 更新策略
     */
    private final FillSegmentUpdater fillSegmentUpdater;

    /**
     *  拉取策略
     */
    private final IFetchPolicy iFetchPolicy;

    private final String tag;

    private Throwable e;

    private static final String THE_SAFE = "theUnsafe";

    static {
        try {
            Field theUnsafe = Unsafe.class.getDeclaredField(THE_SAFE);
            theUnsafe.setAccessible(true);
            UNSAFE = (Unsafe) theUnsafe.get(null);
            STATE_OFFSET = UNSAFE.objectFieldOffset(SegmentBuffer.class.getDeclaredField("state"));
        } catch (Exception e) {
            throw new BizException(e.getMessage(), e);
        }
    }

    public SegmentBuffer(ILeafInfoService leafInfoService, FillSegmentUpdater fillSegmentUpdater, IFetchPolicy iFetchPolicy, String tag) {
        this.leafInfoService = leafInfoService;
        this.fillSegmentUpdater = fillSegmentUpdater;
        this.iFetchPolicy = iFetchPolicy;
        this.tag = tag;

        //初始化一个空的
        init();
    }




    public IDWrapper nextID(int num) {

        /**
         *  检测是否异常
         */
        checkException();

        /**
         *  检测 segment  事件通知
         */
        checkSegment();

        /**
         *  IDWrapper
         */
        IDWrapper idWrapper;
        for (; ; ) {
            //返回不为空就是不需要扩容
            idWrapper = curSegment.nextID(num);  //  3


            if (idWrapper == null) {
                // wait until next segment ok  等待直到缓存准备好
                //再次检测 等到填充
                checkSegment(); //扩充  避免高并发下 走到3 变为空 触发扩容
                for (; ; ) {
                    checkException();
                    //填充好了
                    if (state == NORMAL) {
                        break;
                    }
                    // cas  FILLED 填满
                    if (state == FILLED_NEXT_BUFFER && nextSegment != null && compareAndSwapState(FILLED_NEXT_BUFFER, CHANGE_NEXT_BUFFER)) {
                        log.info("{},next segment ok", tag);
                        changeSegmentAndNotify();
                        break;
                    }
                    synchronized (this) {
                        try {
                            //等待填充  其他没抢到的线程等待
                            this.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            } else {
                /**
                 *  跳出循环
                 */
                break;
            }
        }
        return idWrapper;
    }


    public void setNextSegment(Segment segment) {
        this.nextSegment = segment;
    }

    public void fillComplete(Throwable e) {
        this.e = e;

        //完场填充
        state = FILLED_NEXT_BUFFER;
        synchronized (this) {
            this.notify();
        }
    }

    /**
     * 检查填充是否发生异常
     */
    private void checkException() {
        if (e != null) {
            if (e instanceof BizException) {
                throw (BizException) e;
            } else {
                throw new BizException("检测到异常,tag{" + tag + "}", e);
            }
        }
    }

    /**
     * 交换段缓冲
     */
    private void changeSegmentAndNotify() {
        //交换buffer
        curSegment = nextSegment;
        nextSegment = null;
        state = NORMAL;
        synchronized (this) {
            //唤醒所有等待线程
            this.notifyAll();
        }
    }



    private void init() {
        //初始化一个空的
        curSegment = new Segment();
    }

    /**
     * 检查是否达到切换填充下一个缓冲的比例
     */
    private void checkSegment() {
        // 达到填充阈值 且 下一个缓冲区为空 且 没有存在争用的状态下      0.9 阈值
        if (curSegment.usedPercent().compareTo(iFetchPolicy.nextSegFetchPercent(this.tag)) >= 0
                && nextSegment == null
                && compareAndSwapState(NORMAL, FILLING_NEXT_BUFFER)) {   //状态位控制
            // 构建填充消息
            log.info("开始填充:{}", tag);
            //事件
            FillSegmentEvent fillSegmentEvent = new FillSegmentEvent(this, this.leafInfoService, iFetchPolicy.segmentFetchSize(this.tag), tag);
            //唤醒事件
            fillSegmentUpdater.notifyFill(fillSegmentEvent);
        }
    }

    private boolean compareAndSwapState(int curState, int newState) {
        return UNSAFE.compareAndSwapInt(this, STATE_OFFSET, curState, newState);
    }
}
